import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;   
import java.math.BigInteger;
import java.net.*;   

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class Server {
	
	public  static boolean editFile = false;
	static int listenTPAPort = 8805;
	static int listenClientPort = 8801;
	static int sendTPAPort = 8806;
	static int sendClientPort = 8803;
	static String TPAAddr = "localhost";
	
	private JFrame frame;
	private static JTextArea textArea;
	private static JButton btnEditData;
	
	public Server() {
		initialize();
	}
	
	private void initialize() {
		frame = new JFrame("Server");
		frame.setBounds(100, 100, 339, 281);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().setLayout(null);
		
		JScrollPane scrollPane = new JScrollPane();
		scrollPane.setBounds(22, 36, 272, 159);
		frame.getContentPane().add(scrollPane);

		textArea = new JTextArea();
		scrollPane.setViewportView(textArea);
		
		JLabel lblMessage = new JLabel("message");
		lblMessage.setBounds(22, 11, 55, 14);
		frame.getContentPane().add(lblMessage);
		
		btnEditData = new JButton("edit data");
		btnEditData.setBounds(22, 206, 139, 23);
		btnEditData.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				editFile = !editFile;
				if (editFile){
					textArea.append("data will be modified\n");
					btnEditData.setText("cancel edit data");
				}
				else{
					textArea.append("data will not be modified\n");
					btnEditData.setText("edit Data");
				}
			}
		});
		frame.getContentPane().add(btnEditData);
	}
	
private class ClientSocket extends Thread{
	public void run() {
		ServerSocket serverToClient;
		try {
			serverToClient = new ServerSocket(listenClientPort);
			
			while(true){   	
			Socket client=serverToClient.accept();
			DataInputStream din = new DataInputStream(client.getInputStream());
			String fileName = din.readUTF();
			textArea.append("receive file:"+ fileName +" from client\n");
			textArea.setCaretPosition(textArea.getDocument().getLength()-1);
			File file = new File(fileName);
			FileOutputStream fout = new FileOutputStream(file);
			byte[] buffer = new byte[4096];	
			
			int v = din.readInt();
			int w = din.readInt();
			int u = din.readInt();
			int fileLen = din.readInt();
			
			int remainByte = fileLen;
			int byteRead;
			
			while(remainByte > 0){   
				byteRead = Math.min(remainByte, 4096);
				byteRead=din.read(buffer, 0, byteRead);
				System.out.println("byteRead is:"+byteRead);
				if (editFile) {
					int editTime = (int)(Math.random()*byteRead);
					for (int i = 0; i < editTime; i++) {
						int editBlockNum =(int)(Math.random()*byteRead);
						buffer[editBlockNum] = 1;
					}
				}
				fout.write(buffer, 0, byteRead);
				remainByte -= byteRead;
			}   
			fout.close();

			File file2 = new File(fileName +"_signatureFile");
			BufferedWriter fout2 = new BufferedWriter(new FileWriter(file2));  
			int blockNum = (fileLen - 1) / GenProof.blockLen + 1;
			
			//int[] signature = new int [blockNum];
			//fout2.write(blockNum+"\n");
			//for (int i = 0; i < signature.length; i++) {
			//	signature[i] = din.readInt();
			//	fout2.write(signature[i]+"\n");
			//}
			
			BigInteger[] signature = new BigInteger[blockNum];
			fout2.write(blockNum+"\n");
			for (int i = 0; i < signature.length; i++){
				String s = din.readLine();
				System.out.println(s);
				fout2.write(s+"\n");
			}
			
			fout2.close();

			client.close();
		}
		} 
		catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

class TPASocket extends Thread{
	public void run() {
		ServerSocket serverToTPA;
		try {
			serverToTPA = new ServerSocket(listenTPAPort);
			
			while(true){   	
			Socket tpa=serverToTPA.accept();
			
			DataInputStream din = new DataInputStream(tpa.getInputStream());
			
			String fileName = din.readUTF();
			System.out.print(fileName);
			BufferedReader signatureFile = new BufferedReader(new FileReader(fileName+"_signatureFile"));
			int blockNum = Integer.parseInt(signatureFile.readLine());
			
			//int[] signature = new int[blockNum];
			//for (int i = 0; i < blockNum; i++) {
			//	signature[i] = Integer.parseInt(signatureFile.readLine());
			//}
			
			BigInteger[] signature = new BigInteger[blockNum];
			for (int i = 0 ; i < blockNum ; i++){
				signature[i] = new BigInteger(signatureFile.readLine());
				System.out.println("read signature is:"+signature[i].toString());
			}
			
			
			int v = din.readInt();
			int w = din.readInt();
			int u = din.readInt();
			
			int c = din.readInt();
			System.out.print("received:c:"+c);
			int[][] chal = new int [2][c];
			for (int i = 0; i < c; i++) {
				chal[0][i] = din.readInt();
				chal[1][i] = din.readInt();
				System.out.println(chal[0][i]+","+chal[1][i]);
			}
			
			textArea.append("receive challeng msg from TPA\n");
			textArea.setCaretPosition(textArea.getDocument().getLength()-1);
			GenProof genProof = new GenProof();
			genProof.genProof(chal, signature, fileName);
			System.out.print("miu:"+genProof.getMiu());
			
			Socket server = new Socket(TPAAddr, sendTPAPort);
			OutputStream os2server = server.getOutputStream();
			DataOutputStream dout2server = new DataOutputStream(os2server);

			dout2server.writeUTF(fileName);
			dout2server.writeInt(v);
			dout2server.writeInt(w);
			dout2server.writeInt(u);
			dout2server.writeUTF(genProof.getMiu());
			dout2server.writeUTF(genProof.getSigma());
			dout2server.writeInt(genProof.getR());
			dout2server.writeInt(c);
			
			System.out.println(fileName+","+v+","+w+","+u+","+genProof.getMiu()+","+genProof.getSigma()
					+","+genProof.getR()+","+c);
			
			for(int i = 0; i < c; i++){
				dout2server.writeInt(chal[0][i]);
				dout2server.writeInt(chal[1][i]);
			}
			dout2server.flush();
			
			server.shutdownOutput();
			tpa.close();
			server.close();
		}
		} 
		catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
	
	public static void main(String[] args) throws IOException{
		
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					
					Server window = new Server();
					ClientSocket clientSocket = window.new ClientSocket();
					clientSocket.start();
							
					TPASocket tpaSocket = window.new TPASocket();
					tpaSocket.start();
					window.frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}
}
